home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 31
/
Aminet 31 (1999)(Schatztruhe)[!][Jun 1999].iso
/
Aminet
/
dev
/
c
/
vbccppcsrc.lha
/
vbcc
/
pasm
/
tables.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-03-07
|
10KB
|
345 lines
/* $VER: pasm tables.c V1.2 (24.10.98)
*
* This file is part of pasm, a portable PowerPC assembler.
* Copyright (c) 1997-98 Frank Wille
*
* pasm is freeware and part of the portable and retargetable ANSI C
* compiler vbcc, copyright (c) 1995-98 by Volker Barthelmann.
* pasm may be freely redistributed as long as no modifications are
* made and nothing is charged for it. Non-commercial usage is allowed
* without any restrictions.
* EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
* SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
*
*
* v1.2 (24.10.98) phx
* An empty section with reloc symbols will no longer be deleted.
* v0.8 (14.02.98) phx
* Alignment list for each section. This fixes the problems
* with optimizations.
* v0.7 (01.01.98) phx
* search_instr() is global.
* v0.5 (08.10.97) phx
* .globl directive declares unknown symbols in pass 1 as
* externally defined. If the symbol is defined later in the
* source, it will be made global by add_symbol().
* v0.3 (05.04.97) phx
* Minor changes.
* v0.2 (25.03.97) phx
* Writes ELF object for 32-bit PowerPC big-endian. Either absolute
* or ELF output format may be selected. ELF is default for all
* currently supported platforms. PPCasm supports nine different
* relocation types (there are much more...).
* Compiles and works also under NetBSD/amiga (68k).
* Changed function declaration to 'new style' in all sources
* (to avoid problems with '...' for example).
* Externally defined symbols will automatically get global binding.
* v0.1 (11.03.97) phx
* First test version with all PowerPC instructions and most
* important directives. Only raw, absolute output.
* v0.0 (22.02.97) phx
* File created.
*/
#define TABLES_C
#include "ppcasm.h"
void init_hashtables(struct GlobalVars *);
void add_macro(struct GlobalVars *,struct Macro *);
struct Symbol *add_symbol(struct GlobalVars *,char *,uint8,uint32);
unsigned long elf_hash(unsigned char *);
struct Symbol *search_symbol(struct GlobalVars *,char *);
struct CPUInstr *search_instr(struct GlobalVars *,char *);
struct Section *search_section(struct GlobalVars *,char *);
void search_opcode(struct GlobalVars *,struct ParsedLine *,char *,char *);
static void *alloc_hashtable(size_t);
static void add_instruction(struct GlobalVars *,struct CPUInstr *);
static void add_directive(struct GlobalVars *,struct Directive *);
static struct Directive *search_directive(struct GlobalVars *,char *);
static struct Macro *search_macro(struct GlobalVars *,char *);
static void execute_macro(struct GlobalVars *,struct ParsedLine *);
static void execute_directive(struct GlobalVars *,struct ParsedLine *);
void init_hashtables(struct GlobalVars *gv)
{
struct CPUInstr *ins = instructions;
struct Directive *dir = directives;
gv->symbols = alloc_hashtable(SYMHTABSIZE);
gv->instr = alloc_hashtable(INSTRHTABSIZE);
gv->directives = alloc_hashtable(DIRHTABSIZE);
gv->macros = alloc_hashtable(MACROHTABSIZE);
while (ins->name)
add_instruction(gv,ins++);
while (dir->name)
add_directive(gv,dir++);
}
static void *alloc_hashtable(size_t entries)
{
return (alloczero(entries * sizeof(void *)));
}
static void add_instruction(struct GlobalVars *gv,struct CPUInstr *ins)
/* make new entry into instruction hash table */
{
struct CPUInstr *chain;
unsigned long offs = elf_hash(ins->name)%INSTRHTABSIZE;
if (!(ins->flags & F_EXTENDED) || !gv->noextmnemo) {
if (chain = gv->instr[offs])
ins->hash_chain = chain;
else
ins->hash_chain = NULL;
gv->instr[offs] = ins;
}
}
static void add_directive(struct GlobalVars *gv,struct Directive *dir)
/* make new entry into directive hash table */
{
struct Directive *chain;
unsigned long offs = elf_hash(dir->name)%DIRHTABSIZE;
if (chain = gv->directives[offs])
dir->hash_chain = chain;
else
dir->hash_chain = NULL;
gv->directives[offs] = dir;
}
void add_macro(struct GlobalVars *gv,struct Macro *mac)
/* make new entry into macro hash table */
{
struct Macro *chain,*m;
unsigned long offs = elf_hash(mac->name)%MACROHTABSIZE;
if (chain = m = gv->macros[offs]) { /* hash code already used? */
do {
if (!strcmp(m->name,mac->name)) {
error(8,mac->name); /* macro defined twice! */
break;
}
}
while (m = m->hash_chain);
}
gv->macros[offs] = mac;
mac->hash_chain = chain;
}
struct Symbol *add_symbol(struct GlobalVars *gv,char *name,uint8 type,
uint32 value)
/* define new symbol - absolute, relocatable or external */
{
struct Symbol *sym,*chain;
unsigned long offs = elf_hash(name)%SYMHTABSIZE;
if (chain = sym = gv->symbols[offs]) { /* hash code already used? */
do {
if (!strcmp(name,sym->name)) {
if (sym->type == SYM_EXTERN) { /* declared ext. visible by .globl? */
if ((sym->type = type) == SYM_RELOC) {
struct Section *cs = gv->csect;
sym->relsect = cs;
cs->flags |= SF_HASSYMS;
sym->alignpoint = cs->current_align;
}
sym->value = value;
}
else
error(7,name); /* symbol defined twice! */
return (sym);
}
}
while (sym = sym->hash_chain);
}
gv->symbols[offs] = sym = alloczero(sizeof(struct Symbol));
sym->hash_chain = chain;
sym->name = allocstring(name);
sym->value = value;
if ((sym->type = type) == SYM_RELOC) {
sym->relsect = gv->csect;
sym->alignpoint = gv->csect->current_align;
}
else if (type == SYM_EXTERN) {
sym->bind = SYMB_GLOBAL;
if (sym->type==SYM_RELOC)
sym->relsect->flags |= SF_HASSYMS;
}
return (sym);
}
unsigned long elf_hash(unsigned char *name)
/* calculate a hash code as used in ELF objects */
{
unsigned long h=0,g;
while (*name) {
h = (h << 4) + *name++;
if (g = h & 0xf0000000)
h ^= g >> 24;
h &= ~g;
}
return (h);
}
struct Symbol *search_symbol(struct GlobalVars *gv,char *name)
/* find a symbol in the symbol hash table */
{
struct Symbol *chain;
unsigned long offs = elf_hash(name)%SYMHTABSIZE;
chain = gv->symbols[offs];
while (chain) {
if (!strcmp(chain->name,name))
return (chain);
chain = chain->hash_chain;
}
return (NULL);
}
struct CPUInstr *search_instr(struct GlobalVars *gv,char *name)
/* find an instruction in the instruction hash table */
{
struct CPUInstr *chain;
unsigned long offs = elf_hash(name)%INSTRHTABSIZE;
chain = gv->instr[offs];
while (chain) {
if (!strcmp(chain->name,name))
return (chain);
chain = chain->hash_chain;
}
return (NULL);
}
static struct Directive *search_directive(struct GlobalVars *gv,char *name)
/* find a directive in the directive hash table */
{
struct Directive *chain;
unsigned long offs = elf_hash(name)%DIRHTABSIZE;
chain = gv->directives[offs];
while (chain) {
if (!strcmp(chain->name,name))
return (chain);
chain = chain->hash_chain;
}
return (NULL);
}
static struct Macro *search_macro(struct GlobalVars *gv,char *name)
/* find a macro in the macro hash table */
{
struct Macro *chain;
unsigned long offs = elf_hash(name)%MACROHTABSIZE;
chain = gv->macros[offs];
while (chain) {
if (!strcmp(chain->name,name))
return (chain);
chain = chain->hash_chain;
}
return (NULL);
}
struct Section *search_section(struct GlobalVars *gv,char *name)
{
struct Section *nextsec,*sec=(struct Section *)gv->sectionlist.first;
while (nextsec = (struct Section *)sec->n.next) {
if (!strcmp(name,sec->name))
return (sec);
sec = nextsec;
}
return (NULL);
}
void search_opcode(struct GlobalVars *gv,struct ParsedLine *pl,
char *opname,char *operand)
{
if (gv->alignflag)
pl->flags |= PLF_ALIGN;
gv->alignflag = FALSE;
if (pl->opcode = (void *)search_macro(gv,opname)) {
pl->type = OT_MACRO;
pl->operand = operand;
execute_macro(gv,pl);
}
else if (pl->opcode = (void *)search_instr(gv,opname)) {